#ifndef FORMAT_HPP
#define FORMAT_HPP

#include "message.hpp"
#include <iostream>
#include <sstream>
#include <memory>
#include <unordered_map>
#include <functional>

namespace ly
{
    // 格式化选项:
    // %Y - 年 (2025)
    // %m - 月 (01-12)
    // %d - 日 (01-31)
    // %H - 时 (00-23)
    // %M - 分 (00-59)
    // %S - 秒 (00-59)
    // %l - 日志级别 (info, debug等)
    // %t - 线程ID
    // %n - 日志器名
    // %s - 源文件名
    // %# - 行号
    // %v - 实际的日志消息
    // %% - '%'

    class FormatItem
    {
    public:
        using ptr = std::shared_ptr<FormatItem>;
        virtual ~FormatItem() = default;
        virtual void format(std::stringstream &out, const LogMessage &message) = 0;
    };

    // 一个格式化选项对应一个派生类
    // %Y - 年 (2025)
    class YearFormatItem : public FormatItem
    {
    public:
        virtual void format(std::stringstream &out, const LogMessage &message) override { out << (message._time.tm_year + 1900); }
    };
    // %m - 月 (01-12)
    class MonthFormatItem : public FormatItem
    {
    public:
        virtual void format(std::stringstream &out, const LogMessage &message) override { out << message._time.tm_mon + 1; }
    };
    // %d - 日 (01-31)
    class DayFormatItem : public FormatItem
    {
    public:
        virtual void format(std::stringstream &out, const LogMessage &message) override { out << message._time.tm_mday; }
    };
    // %H - 时 (00-23)
    class HourFormatItem : public FormatItem
    {
    public:
        virtual void format(std::stringstream &out, const LogMessage &message) override { out << message._time.tm_hour; }
    };
    // %M - 分 (00-59)
    class MinuteFormatItem : public FormatItem
    {
    public:
        virtual void format(std::stringstream &out, const LogMessage &message) override { out << message._time.tm_min; }
    };
    // %S - 秒 (00-59)
    class SecondFormatItem : public FormatItem
    {
    public:
        virtual void format(std::stringstream &out, const LogMessage &message) override { out << message._time.tm_sec; }
    };
    // %l - 日志级别 (info, debug等)
    class LevelFormatItem : public FormatItem
    {
    public:
        virtual void format(std::stringstream &out, const LogMessage &message) override { out << LogLevel::levelToString(message._level); }
    };
    // %t - 线程ID
    class ThreadIDFormatItem : public FormatItem
    {
    public:
        virtual void format(std::stringstream &out, const LogMessage &message) override { out << message._tid; }
    };
    // %n - 日志器名
    class LoggerNameFormatItem : public FormatItem
    {
    public:
        virtual void format(std::stringstream &out, const LogMessage &message) override { out << message._logger_name; }
    };
    // %s - 源文件名
    class FileNameFormatItem : public FormatItem
    {
    public:
        virtual void format(std::stringstream &out, const LogMessage &message) override { out << message._file; }
    };
    // %# - 行号
    class LineFormatItem : public FormatItem
    {
    public:
        virtual void format(std::stringstream &out, const LogMessage &message) override { out << message._line; }
    };
    // %v - 实际的日志消息
    class MessageFormatItem : public FormatItem
    {
    public:
        virtual void format(std::stringstream &out, const LogMessage &message) override { out << message._message; }
    };
    // 其他
    class OtherFormatItem : public FormatItem
    {
    public:
        OtherFormatItem(const std::string &str = "") : other_message(str) {}
        virtual void format(std::stringstream &out, const LogMessage &message) override { out << other_message; (void)message; }

    private:
        std::string other_message;
    };

    // 格式化器
    class Formatter
    {
    public:
        using ptr = std::shared_ptr<Formatter>;

    public:
        Formatter(const std::string &pattern = "[%Y-%m-%d %H:%M:%S] [%l] [thread %t] [%s:%#] [%n] %v") { analysis(pattern); }
        // 消息对象 -> 格式化后的消息字符串
        std::string format(const LogMessage &message)
        {
            std::stringstream ss;
            for (auto &e : _formatter_items)
                e->format(ss, message);
            return ss.str();
        }

    private:
        void analysis(const std::string &pattern)
        {
            std::string other_message;
            for (int i = 0, size = pattern.size(); i < size; ++i)
            {
                char c = pattern[i];
                if (c != '%' || i + 1 == size || _creaters.count(pattern[i + 1]) == 0)
                    other_message.append(1, c);
                else
                {
                    c = pattern[++i]; // 将 i 更新至格式化选项处, 将 c 更新为格式化选项
                    if (other_message.size())
                        _formatter_items.push_back(_creaters['O'](other_message));
                    other_message.clear();
                    _formatter_items.push_back(_creaters[c](""));
                }
            }
        }

    private:
        std::string _pattern;                          // 格式化字符串
        std::vector<FormatItem::ptr> _formatter_items; // 解析_pattern得到_formatter_items
        static std::unordered_map<char, std::function<FormatItem::ptr(const std::string &)>> _creaters;
    };

    std::unordered_map<char, std::function<FormatItem::ptr(const std::string &)>> Formatter::_creaters{
        {'Y', [](const std::string &) -> FormatItem::ptr
         { return std::make_shared<YearFormatItem>(); }},
        {'m', [](const std::string &) -> FormatItem::ptr
         { return std::make_shared<MonthFormatItem>(); }},
        {'d', [](const std::string &) -> FormatItem::ptr
         { return std::make_shared<DayFormatItem>(); }},
        {'H', [](const std::string &) -> FormatItem::ptr
         { return std::make_shared<HourFormatItem>(); }},
        {'M', [](const std::string &) -> FormatItem::ptr
         { return std::make_shared<MinuteFormatItem>(); }},
        {'S', [](const std::string &) -> FormatItem::ptr
         { return std::make_shared<SecondFormatItem>(); }},
        {'l', [](const std::string &) -> FormatItem::ptr
         { return std::make_shared<LevelFormatItem>(); }},
        {'t', [](const std::string &) -> FormatItem::ptr
         { return std::make_shared<ThreadIDFormatItem>(); }},
        {'n', [](const std::string &) -> FormatItem::ptr
         { return std::make_shared<LoggerNameFormatItem>(); }},
        {'s', [](const std::string &) -> FormatItem::ptr
         { return std::make_shared<FileNameFormatItem>(); }},
        {'#', [](const std::string &) -> FormatItem::ptr
         { return std::make_shared<LineFormatItem>(); }},
        {'v', [](const std::string &) -> FormatItem::ptr
         { return std::make_shared<MessageFormatItem>(); }},
        {'O', [](const std::string &s) -> FormatItem::ptr
         { return std::make_shared<OtherFormatItem>(s); }},
    };
} // namespace ly

#endif // FORMAT_HPP